import {
  defineComponent,
  nextTick,
  onMounted,
  onUnmounted,
  ref,
  watch,
} from 'vue';
import './monaco-editor.scss';
import {
  getCodeProps,
  getEditorEmits,
  useNamespace,
  useUIStore,
} from '@ibiz-template/vue3-util';
import { ElMessageBox } from 'element-plus';
import * as monaco from 'monaco-editor';
import loader from '@monaco-editor/loader';
import { CodeEditorController } from '../code-editor.controller';

export const IBizCode = defineComponent({
  name: 'IBizCode',
  props: getCodeProps<CodeEditorController>(),
  emits: getEditorEmits(),
  setup(props, { emit }) {
    const ns = useNamespace('code');

    const c = props.controller!;

    const currentVal = ref<string>('');

    // 允许编辑
    const enableEdit = ref(true);

    // 是否存在编辑器参数enableEdit
    const hasEnableEdit = ref(false);

    // 只读状态
    const readonlyState = ref(false);

    // 允许全屏打开
    const enableFullScreen = ref(false);

    // 是否全屏
    const isFullScreen = ref(false);

    const editorModel = c.model;
    if (editorModel.editorParams) {
      if (editorModel.editorParams.enableEdit) {
        hasEnableEdit.value = true;
        readonlyState.value = true;
        enableEdit.value =
          c.toBoolean(editorModel.editorParams.enableEdit) &&
          !props.readonly &&
          !props.disabled;
      }
      if (editorModel.editorParams.enableFullScreen) {
        enableFullScreen.value = c.toBoolean(
          editorModel.editorParams.enableFullScreen,
        );
      }
    }

    let editor: monaco.editor.IStandaloneCodeEditor | null;
    let monacoEditor: typeof monaco.editor;
    const { UIStore } = useUIStore();

    // 编辑器主题
    const getMonacoTheme = (name: string): string => {
      return name === 'dark' ? `vs-${UIStore.theme}` : 'vs'; // 官方自带三种主题vs, hc-black, or vs-dark
    };

    watch(
      () => UIStore.theme,
      newVal => {
        monacoEditor.setTheme(getMonacoTheme(newVal));
      },
    );

    watch(
      () => props.value,
      newVal => {
        if (newVal !== currentVal.value) {
          currentVal.value = newVal || '';
          editor?.setValue(currentVal.value);
        }
      },
      { immediate: true },
    );

    // 更新编辑器配置
    const updateEditorOptions = () => {
      if (!editor) {
        return;
      }
      if (props.readonly || props.disabled) {
        hasEnableEdit.value = false;
        readonlyState.value = true;
      }
      editor.updateOptions({
        readOnly: hasEnableEdit.value
          ? readonlyState.value
          : props.readonly || props.disabled,
      });
    };

    watch(() => props.readonly, updateEditorOptions, { immediate: true });

    watch(() => props.disabled, updateEditorOptions, { immediate: true });

    const codeEditBox = ref();

    const editorInit = (): void => {
      nextTick(() => {
        loader.config({
          paths: {
            vs: `${ibiz.env.pluginBaseUrl}/monaco-editor@0.45.0/min/vs`,
          },
        });
        loader.init().then(loaderMonaco => {
          // 初始化编辑器
          if (!editor) {
            monacoEditor = loaderMonaco.editor;
            editor = monacoEditor.create(codeEditBox.value, {
              language: props.language || props.controller.language, // 语言支持自行查阅demo
              theme: getMonacoTheme(UIStore.theme),
              foldingStrategy: 'indentation',
              renderLineHighlight: 'all', // 行亮
              selectOnLineNumbers: true, // 显示行号
              minimap: {
                enabled: true,
              },
              readOnly: hasEnableEdit.value
                ? readonlyState.value
                : props.readonly || props.disabled, // 只读
              readOnlyMessage: {
                value: ibiz.i18n.t('editor.code.readOnlyPrompt'),
              },
              fontSize: 16, // 字体大小
              scrollBeyondLastLine: false, // 取消代码后面一大段空白
              overviewRulerBorder: false, // 不要滚动条的边框
            });
          }
          setTimeout(() => {
            editor!.layout();
            editor!.setValue(currentVal.value);
          });

          // 监听值的变化
          editor.onDidChangeModelContent(() => {
            if (!hasEnableEdit.value) {
              currentVal.value = editor!.getValue();
              emit('change', currentVal.value);
            }
          });

          window.addEventListener('resize', () => {
            editor!.layout();
          });
        });
      });
    };

    // 更改编辑状态
    const changeEditState = () => {
      readonlyState.value = !readonlyState.value;
      if (!editor) return;
      if (!readonlyState.value) {
        editor.updateOptions({
          readOnly: false,
        });
      } else {
        editor.updateOptions({
          readOnly: true,
        });
      }
    };

    // 更新全屏状态
    const changeFullScreenState = async () => {
      currentVal.value = String(editor?.getValue());
      editor?.dispose();
      editor = null;
      isFullScreen.value = !isFullScreen.value;
      editorInit();
    };

    // 绘制全屏图标
    const isAllowRenderFullScreen = () => {
      if (enableFullScreen.value) {
        if (isFullScreen.value) {
          return (
            <i
              class='fa fa-compress'
              aria-hidden='true'
              onClick={() => changeFullScreenState()}
            ></i>
          );
        }
        return (
          <i
            class='fa fa-expand'
            aria-hidden='true'
            onClick={() => changeFullScreenState()}
          ></i>
        );
      }
      return null;
    };

    // 绘制取消消息盒子
    const renderCancelMessage = () => {
      return (
        <div class={ns.be('message', 'message-content')}>
          <p>{ibiz.i18n.t('editor.code.confirmCancelPrompt')}</p>
          <p class={ns.bem('message', 'message-content', 'message-tip')}>
            {ibiz.i18n.t('editor.code.cancelEditPrompt')}
          </p>
        </div>
      );
    };

    // 取消编辑
    const cancelEdit = () => {
      if (props.value !== editor?.getValue()) {
        ElMessageBox({
          title: ibiz.i18n.t('editor.code.confirmCancel'),
          type: 'warning',
          customClass: ns.b('message'),
          message: renderCancelMessage(),
          showCancelButton: true,
          cancelButtonClass: ns.be('message', 'message-cancel'),
          confirmButtonClass: ns.be('message', 'message-comfire'),
        })
          .then(() => {
            editor?.setValue(String(props.value || ''));
            changeEditState();
          })
          .catch(() => {
            // 重新聚焦
            editor?.focus();
          });
      } else {
        changeEditState();
      }
    };

    // 确认保存
    const save = () => {
      changeEditState();
      if (editor) {
        currentVal.value = editor!.getValue();
        emit('change', currentVal.value);
      }
      if (isFullScreen.value) {
        changeFullScreenState();
      }
    };

    // 绘制底部取消确认按钮
    const renderFooter = () => {
      if (hasEnableEdit.value) {
        return (
          <div
            class={[
              ns.b('footer'),
              { [ns.b('footer-dialog')]: isFullScreen.value },
            ]}
          >
            <div class={ns.be('footer', 'cancel')} onClick={() => cancelEdit()}>
              {ibiz.i18n.t('app.cancel')}
            </div>
            <div class={ns.be('footer', 'save')} onClick={() => save()}>
              {ibiz.i18n.t('app.save')}
            </div>
          </div>
        );
      }
      return null;
    };

    // 绘制头部工具栏
    const renderHeaderToolbar = () => {
      if (hasEnableEdit.value || enableFullScreen.value) {
        return (
          <div class={ns.b('toolbar')}>
            {hasEnableEdit.value && enableEdit.value && readonlyState.value ? (
              <i
                class='fa fa-edit'
                aria-hidden='true'
                onClick={() => changeEditState()}
              ></i>
            ) : null}
            {isAllowRenderFullScreen()}
          </div>
        );
      }
      return null;
    };

    // 绘制代码框内容
    const renderCodeContent = () => {
      return <div ref={codeEditBox} class={ns.e('box')}></div>;
    };

    onMounted(() => {
      editorInit();
    });

    onUnmounted(() => {
      editor?.dispose();
    });

    return {
      ns,
      currentVal,
      codeEditBox,
      isFullScreen,
      hasEnableEdit,
      readonlyState,
      renderFooter,
      renderHeaderToolbar,
      renderCodeContent,
      changeFullScreenState,
    };
  },
  render() {
    return !this.isFullScreen ? (
      <div
        class={[
          this.ns.b(),
          { [this.ns.b('editor-readonly')]: this.readonlyState },
          { [this.ns.b('editor-enable')]: !this.readonlyState },
        ]}
      >
        {this.renderHeaderToolbar()}
        {this.renderCodeContent()}
        {this.hasEnableEdit && !this.readonlyState ? this.renderFooter() : null}
      </div>
    ) : (
      <el-dialog
        v-model={this.isFullScreen}
        width='80%'
        top='10vh'
        class={this.ns.b('dialog-full-screen')}
        onClose={() => this.changeFullScreenState()}
      >
        <div
          class={[
            this.ns.b(),
            { [this.ns.b('editor-readonly')]: this.readonlyState },
            { [this.ns.b('editor-enable')]: !this.readonlyState },
          ]}
        >
          {this.renderHeaderToolbar()}
          {this.renderCodeContent()}
          {this.hasEnableEdit && !this.readonlyState
            ? this.renderFooter()
            : null}
        </div>
      </el-dialog>
    );
  },
});
